//--------------------------------------------------------------------------------------
//v6_filter
//--------------------------------------------------------------------------------------
// D_k(n) = exp(n) - exp(n-k)
// D_1(n) = exp(n) - exp(n-1)
// P(n) = P(n-1) + D_k(n) - k * d_1(n-l), {n>=0}
// Q(n) = Q(n-1) + M2 * P(n), {n>=0}
// Res(n) = Res(n-1) + Q(n) + M1 * P(n), {n>=0}
//--------------------------------------------------------------------------------------
import package_settings::*;
import V6_parameter::*;
//--------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------
module v6_filter (
//--------------------------------------------------------------------------------------
// Input Ports
//--------------------------------------------------------------------------------------
	input  wire                                                  clk,
	input  wire                                                  reset,
//--------------------------------------------------------------------------------------
	input  wire [SIZE_ADC_DATA-1:0]                              input_data,
//--------------------------------------------------------------------------------------
// Output Ports
//--------------------------------------------------------------------------------------
	output reg  [SIZE_FILTER_DATA-1:0]                           output_data);
//--------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------

	reg signed        [(SIZE_ADC_DATA-1)*4:0]                                signal_delay [K_v6:0];

	reg signed        [(SIZE_ADC_DATA-1)*4:0]                                Dk;
	reg signed        [(SIZE_ADC_DATA-1)*4:0]                                D1;
	
	reg signed        [(SIZE_ADC_DATA-1)*4:0]                                D1_delay [L_v6-1:0];
	reg signed        [(SIZE_ADC_DATA-1)*4:0]                                K_D1;
	reg signed        [(SIZE_ADC_DATA-1)*4:0]                                Dk_delay;
	reg signed        [(SIZE_ADC_DATA-1)*4:0]                                Dk_K_D1;
	reg signed        [(SIZE_ADC_DATA-1)*4:0]                                P;
	
	reg signed        [(SIZE_ADC_DATA-1)*4:0]                                M2_P;
	reg signed        [(SIZE_ADC_DATA-1)*4:0]                                Q;
	
	reg signed        [(SIZE_ADC_DATA-1)*4:0]                                M1_P;
	reg signed        [(SIZE_ADC_DATA-1)*4:0]                                Q_delay;
	reg signed        [(SIZE_ADC_DATA-1)*4:0]                                Q_M1_P;
	reg signed        [(SIZE_ADC_DATA-1)*4:0]                                Res;

	always @ (posedge clk or negedge reset) begin
		if (!reset) begin
		//--------------------------------------------------------------------------------------
			Dk															<= 0;
			D1															<= 0;
			
			D1_delay [0]												<= 0;
			for (integer i = 1; i <= L_v6-1; i++) begin
				D1_delay[i]												<= 0;
			end
			K_D1														<= 0;
			Dk_delay													<= 0;
			Dk_K_D1														<= 0;
			P															<= 0;
			
			M2_P														<= 0;
			Q															<= 0;
			
			M1_P														<= 0;
			Q_delay														<= 0;
			Q_M1_P														<= 0;
			Res															<= 0;
			
			for (integer i = 0; i <= K_v6; i++) begin
				signal_delay[i]											<= 0;
			end
			output_data													<= 0;
		//--------------------------------------------------------------------------------------
		end else begin
		//--------------------------------------------------------------------------------------
			signal_delay[0]												<= input_data;
			for (integer i = 1; i <= K_v6; i++) begin
				signal_delay[i]											<= signal_delay[i-1];
			end
			Dk															<= signal_delay[0] - signal_delay[K_v6];
			D1															<= signal_delay[0] - signal_delay[1];
			
			D1_delay [0]												<= D1;
			for (integer i = 1; i <= L_v6 - 1; i++) begin
				D1_delay[i]												<= D1_delay[i-1];
			end
			
			K_D1														<= K_v6 * D1_delay[L_v6-1];
			Dk_delay													<= Dk;
			Dk_K_D1														<= Dk_delay - K_D1;
			P															<= P + Dk_K_D1;

			M2_P														<= M2_v6 * P;
			Q															<= Q + M2_P;
			
			M1_P														<= M1_v6 * P;
			Q_delay														<= Q;
			Q_M1_P														<= Q_delay + M1_P;
			Res															<= Res + Q_M1_P;
/*
			if (Res & (1 << (SIZE_ADC_DATA-1)*4) == 0) begin
				if (Res & (1 << 8) == 1)begin
					output_data											<= (Res >>> 8) + 1;
				end else begin
					output_data											<= Res >>> 8;
				end
			end
			if (Res & (1 << (SIZE_ADC_DATA-1)*4) == 1) begin
				if (((Res & 1) == 0) && (|Res)) begin
					output_data											<= (Res >>> 8) + 1;
				end else begin
					output_data											<= Res >>> 8;
				end
			end
*/
			output_data											<= Res >>> 8;
		//--------------------------------------------------------------------------------------
		end
	end

endmodule